package com.woniuxy.threadmethods;

import com.woniuxy.untis.Sleep;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

/**
 * <P> @Author: ideaAdmin
 * <P> TODO: Class
 * <P> TODO: 同步模式是保护性暂停
 * <P> Date: 2022/4/7:15:11
 * <P> Description:
 */
@Slf4j(topic = "c.Test21")
public class Test21 {

    public static void main(String[] args) {

        for (int i = 0; i < 3; i++) {
            new People().start();
        }

        Sleep.sleep(1000);

        for (Integer id : MailBoxes.getIdS()) {
            new Postman(id, "内容" + id).start();
        }

    }
}

/**
 * TODO: 邮递员
 **/
@Slf4j(topic = "c.Postman")
class Postman extends Thread {
    private int id;

    /**
     * TODO 邮件内容
     */
    private String mail;

    public Postman(int id, String mail) {
        this.id = id;
        this.mail = mail;
    }


    /**
     * TODO:传递邮件
     **/
    @Override
    public void run() {
        GuardedObject1 guardedObject = MailBoxes.getGuardedObject(id);
        log.debug("送信,id:{},内容:{}", guardedObject.getId(), mail);
        guardedObject.complete(mail);
    }
}


@Slf4j(topic = "c.People")
@Data
class People extends Thread {

    @Override
    public void run() {
        //收信
        GuardedObject1 guardedObject = MailBoxes.createGuardedObject();
        log.debug("开始收信,id:{}", guardedObject.getId());
        Object mail = guardedObject.get(5000);
        log.debug("收信,id:{},内容:{}", guardedObject.getId(), mail);
    }
}

/**
 * TODO:邮箱
 **/
class MailBoxes {
    private static Map<Integer, GuardedObject1> boxes = new Hashtable<>();

    private static int id = 1;

    /**
     * TODO:返回对应存入的邮件
     **/
    public static GuardedObject1 getGuardedObject(int id) {
        return boxes.remove(id);
    }

    /**
     * TODO:产生唯一id
     **/
    private static int generateId() {
        synchronized (MailBoxes.class) {
            return id++;
        }
    }

    /**
     * TODO:创建GuardedObject1
     **/
    public static GuardedObject1 createGuardedObject() {
        GuardedObject1 go = new GuardedObject1(generateId());
        boxes.put(go.getId(), go);
        return go;
    }

    /**
     * TODO:返回所有的key
     **/
    public static Set<Integer> getIdS() {
        return boxes.keySet();
    }


}

@Data
class GuardedObject1 {
    /**
     * TODO 标识 GuardedObject
     */
    private int id;


    /**
     * TODO 结果
     */
    private Object response;

    public GuardedObject1(int id) {
        this.id = id;
    }

    /**
     * TODO: 提取结果
     **/
    public Object get(long outTime) {
        synchronized (this) {
            //记录开始时间
            long begin = System.currentTimeMillis();

            //记录经历的时间
            long passedTime = 0;

            while (response == null) {

                long waitTime = outTime - passedTime;
                //如果经历时间超过最大等待时间
                if (waitTime <= 0) {
                    break;
                }
                try {
                    //TODO 虚假唤醒 限定他的超时 获得接下来还需要等待的时间

                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passedTime = System.currentTimeMillis() - begin;
            }
            return response;
        }
    }

    /**
     * TODO:产生结果
     **/
    public void complete(Object response) {
        synchronized (this) {
            this.response = response;
            this.notifyAll();
        }
    }

}
